﻿/**************************************************************
 * Project     : Titan Framework
 * Copyright (C) 2011 Microsoft Corp.
 * Author      : Julian Hu
 * Mail        : junhu@microsoft.com
 * Create Date : 2011-05-10
 * Summary     :   
 * 
 * 
 * Modified By : 
 * Date        : 
 * Mail        : 
 * Comment     :   
 * *************************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.DirectoryServices;
using Titan.Configuration;
using System.Runtime.InteropServices;
using Titan.Logging;

namespace Titan.ActiveDirectory
{
    [Serializable]
    public class ADException :Exception
    {
        public ADException(string message, Exception innerException)
            : base(message, innerException)
        {
        }
    }

    public class ADManager
    {
        /// <summary>
        ///  Get All Users from AD by inputing path
        /// </summary>
        /// <param name="path">the path of AD</param>
        /// <returns></returns>
        /// 

        private static ILogger _logger = new LoggerFactory().GetLogger(System.Reflection.MethodBase.GetCurrentMethod().GetType());

        public static IDictionary<string, string> GetUsers(string path)
        {
            _logger.Debug("start search AD, path="+path);
            IDictionary<string, string> account = new Dictionary<string, string>();
            DirectoryEntry entry = null;
            try
            {
                if (Config.Instance.ADChecked)
                {
                    entry = new DirectoryEntry(path, Config.Instance.LoginName, Config.Instance.Password);
                }
                else
                {
                    entry = new DirectoryEntry(path);
                }
            }
            catch (COMException er)
            {
                throw new ADException("Couldnt connect to the specified Active Directory Path.", er);
            }

            DirectorySearcher mySearcher = new DirectorySearcher(entry);
            if (!string.IsNullOrEmpty(Config.Instance.SchemaClass))
            {
                string strCat = "(objectCategory=" + Config.Instance.SchemaClass + ")";
                mySearcher.Filter = strCat;
            }
            try
            {
                string strAccountName;
                string strAccountCode;
                foreach (SearchResult result in mySearcher.FindAll())
                {
                    strAccountName = result.GetDirectoryEntry().Name;
                    strAccountName = strAccountName.Remove(0, 3);
                    strAccountCode = result.GetDirectoryEntry().Properties[Config.Instance.ADAccountCode].Value.ToString();
                    account.Add(strAccountCode, strAccountName);
                }
            }
            catch (COMException er)
            {
                throw new ADException("Couldnt connect to Active Directory.", er);
            }
            _logger.Debug("end search AD, find users " + account.Count);
            return account;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="strAccountCode"></param>
        /// <returns></returns>
        public static bool VerifyIdentity(string strAccountCode)
        {
            _logger.Debug("start verify identity, account code=" + strAccountCode);
            IDictionary<string, string> account = new Dictionary<string, string>();
            DirectoryEntry entry = null;
            try
            {
                if (Config.Instance.ADChecked)
                {
                    entry = new DirectoryEntry(Config.Instance.LDAP, Config.Instance.LoginName, Config.Instance.Password);
                }
                else
                {
                    entry = new DirectoryEntry(Config.Instance.LDAP);
                }
            }
            catch (COMException er)
            {
                throw new ADException("Couldnt connect to the specified Active Directory Path.", er);
            }

            DirectorySearcher mySearcher = new DirectorySearcher(entry);
            StringBuilder buff = new StringBuilder();
            if (!string.IsNullOrEmpty(Config.Instance.SchemaClass))
            {
                //string strCat = "(objectCategory=" + Config.Instance.SchemaClass + ")";
                buff.AppendFormat("(objectCategory={0})", Config.Instance.SchemaClass);
                //mySearcher.Filter = strCat;
            }

            if (!string.IsNullOrEmpty(strAccountCode))
            {
                buff.AppendFormat("(sAMaccountName={0})", strAccountCode);
            }

            if (buff.Length > 0)
            {
                mySearcher.Filter = string.Format("(&{0})", buff.ToString());    //buff.ToString();
            }

            SearchResult result = mySearcher.FindOne();

            if (result == null)
            {
                return false;
            }
            return true;
        }

        public static bool VerifyIdentity(string strAccountCode, IList<string> ldaps)
        {
            bool isResult = false;
            foreach (string ldap in ldaps)
            {
                IDictionary<string, string> account = new Dictionary<string, string>();
                DirectoryEntry entry = null;
                try
                {
                    if (Config.Instance.ADChecked)
                    {
                        entry = new DirectoryEntry(ldap, Config.Instance.LoginName, Config.Instance.Password);
                    }
                    else
                    {
                        entry = new DirectoryEntry(ldap);
                    }
                }
                catch (COMException er)
                {
                    throw new ADException("Couldnt connect to the specified Active Directory Path.", er);
                }

                DirectorySearcher mySearcher = new DirectorySearcher(entry);
                StringBuilder buff = new StringBuilder();
                if (!string.IsNullOrEmpty(Config.Instance.SchemaClass))
                {
                    buff.AppendFormat("(objectCategory={0})", Config.Instance.SchemaClass);
                }

                if (!string.IsNullOrEmpty(strAccountCode))
                {
                    buff.AppendFormat("(sAMaccountName={0})", strAccountCode);
                }

                if (buff.Length > 0)
                {
                    mySearcher.Filter = string.Format("(&{0})", buff.ToString());    //buff.ToString();
                }

                SearchResult result = mySearcher.FindOne();

                if (result != null)
                {
                    isResult = true;
                    break;
                }
            }
            return isResult;
        }

        public static bool VerifyIdentity(string strAccountCode, ref string strAccountName, IList<string> ldaps)
        {
            bool isResult = false;
            foreach (string ldap in ldaps)
            {
                IDictionary<string, string> account = new Dictionary<string, string>();
                DirectoryEntry entry = null;
                try
                {
                    if (Config.Instance.ADChecked)
                    {
                        entry = new DirectoryEntry(ldap, Config.Instance.LoginName, Config.Instance.Password);
                    }
                    else
                    {
                        entry = new DirectoryEntry(ldap);
                    }
                }
                catch (COMException er)
                {
                    throw new ADException("Couldnt connect to the specified Active Directory Path.", er);
                }

                DirectorySearcher mySearcher = new DirectorySearcher(entry);
                StringBuilder buff = new StringBuilder();
                if (!string.IsNullOrEmpty(Config.Instance.SchemaClass))
                {
                    buff.AppendFormat("(objectCategory={0})", Config.Instance.SchemaClass);
                }

                if (!string.IsNullOrEmpty(strAccountCode))
                {
                    buff.AppendFormat("(sAMaccountName={0})", strAccountCode);
                }

                if (buff.Length > 0)
                {
                    mySearcher.Filter = string.Format("(&{0})", buff.ToString());    //buff.ToString();
                }

                SearchResult result = mySearcher.FindOne();

                if (result != null)
                {
                    strAccountName = result.GetDirectoryEntry().Properties["displayName"].Value.ToString();
                    isResult = true;
                    break;
                }
            }
            return isResult;
        }
    }
}
